/**
 * Copyright 2009-2021 the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package zy.blue7.mybatis.test.xml.util;

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import zy.blue7.mybatis.test.xml.plugins.MYInsertPlugin;

import java.io.IOException;
import java.io.Reader;

/**
 * @author blue7
 * @create 2021/5/17 13:53
 */
public class SqlSessionFactoryUtil {
    public static SqlSessionFactory getSqlSessionFactory() {
        String path = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        try {
            /**
             * 1，读取mybatis配置文件，里面配置了mybatis的一些核心配置，比如数据库链接，等等
             * 2.生成 SqlSessionFactoryBuilder， 用于生成 sqlSessionFactory
             */
            Reader reader = Resources.getResourceAsReader(path);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            /**
             * 下面三种情况都是SqlSessionFactoryBuilder 的build的重载方法
             * environment 对应 todo <environment id="development"/> 标签
             * properties  对应 todo <properties/> 标签，类似于el表达式之类的属性
             */
//            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,"dev");
//            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,new Properties());
//            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,"dev",new Properties());
        } catch (IOException e) {
            System.out.println("获取配置文件失败");
            e.printStackTrace();
        }

        return sqlSessionFactory;
    }

    /**
     * 不通过xml获取  SqlSessionFactory
     * todo 如果你更愿意直接从 Java 代码而不是 XML 文件中创建配置，或者想要创建你自己的配置建造器，MyBatis 也提供了完整的配置类，提供了所有与 XML 文件等价的配置项。
     * <p>
     * 注意该例中，configuration 添加了一个映射器类（mapper class）。映射器类是 Java 类，它们包含 SQL 映射注解从而避免依赖 XML 文件。
     * 不过，由于 Java 注解的一些限制以及某些 MyBatis 映射的复杂性，要使用大多数高级映射（比如：嵌套联合映射），仍然需要使用 XML 配置。
     * 有鉴于此，如果存在一个同名 XML 配置文件，MyBatis 会自动查找并加载它（在这个例子中，基于类路径和 BlogMapper.class 的类名，会加载 BlogMapper.xml）。
     * <p>
     * <p>
     * todo 注意， 在通过  Java编码形式 获取 SqlSessionFactory时， 各种配置也要按顺序 添加，不然就容易出错，
     * todo 比如，当添加 mapper时， 会解析 mapper文件中的 select 标签，但是由于使用别名，这时候如果别名是在 addmapper后添加，就会不知道别名对应哪个类，就会出错
     * configuration
     * (properties?,
     * settings?,
     * typeAliases?,
     * typeHandlers?,
     * objectFactory?,
     * objectWrapperFactory?,
     * reflectorFactory?,
     * plugins?,
     * environments?,
     * databaseIdProvider?,
     * mappers?)
     *
     * @return
     */
    public static SqlSessionFactory getSqlSessionFactoryFromJava() {
//        /**
//         * 设置数据源属性
//         */
//        Properties properties=new Properties();
//        properties.setProperty("driver","com.mysql.jdbc.Driver");
//        properties.setProperty("url","jdbc:mysql://localhost:3306/db_mybatis");
//        properties.setProperty("username","root");
//        properties.setProperty("password","2868463718");
//        /**
//         * 创建数据源工厂，通过工厂创建 数据源
//         */
//        PooledDataSourceFactory dataSourceFactory = new PooledDataSourceFactory();
//        dataSourceFactory.setProperties(properties);
//        DataSource dataSource = dataSourceFactory.getDataSource();

        /**
         * 也可以直接new 数据源
         */
        PooledDataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/db_mybatis", "root", "2868463718");
//        PooledDataSource dataSource=new PooledDataSource();
//        dataSource.setDriver("com.mysql.jdbc.Driver");
//        dataSource.setUrl("jdbc:mysql://localhost:3306/db_mybatis");
//        dataSource.setUsername("root");
//        dataSource.setPassword("2868463718");


        /**
         * 创建事务工厂
         */
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        /**
         * 设置环境变量
         */
        Environment environment = new Environment("development", transactionFactory, dataSource);


        /**
         * 创建 Configuration  相当于  mybatis的配置文件
         */
        Configuration configuration = new Configuration(environment);




        /**
         *
         * todo  settings  标签对应的方法
         *
         *     configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
         *     configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
         *     configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
         *     configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
         *     configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
         *     configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
         *     configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
         *     configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
         *     configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
         *     configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
         *     configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
         *     configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
         *     configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
         *     configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
         *     configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
         *     configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
         *     configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
         *     configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
         *     configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
         *     @SuppressWarnings("unchecked")
         *     Class<? extends TypeHandler> typeHandler = (Class<? extends TypeHandler>)resolveClass(props.getProperty("defaultEnumTypeHandler"));
         *     configuration.setDefaultEnumTypeHandler(typeHandler);
         *     configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
         *     configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
         *     configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
         *     configuration.setLogPrefix(props.getProperty("logPrefix"));
         *     @SuppressWarnings("unchecked")
         *     Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
         *     configuration.setLogImpl(logImpl);
         *     configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
         *
         *
         *
         */


        /**
         * 别名设置
         */
        configuration.getTypeAliasRegistry().registerAliases("zy.blue7.mybatis.test.xml.model");
//        configuration.getTypeAliasRegistry().registerAlias(Object.class);


        /**
         * 类型处理器
         * 对应  标签
         *  <typeHandlers>
         *         <package name="zy.blue7.mybatis.test.xml.typeHandlers"/>
         *         < !--        <typeHandler handler="zy.blue7.mybatis.test.xml.typeHandlers.MyTypeHandler" javaType="zy.blue7.mybatis.test.xml.model.User" jdbcType="VARCHAR"/>-->
         *     </typeHandlers>
         */
//        configuration.getTypeHandlerRegistry().register(Object.class);



        /**
         * 添加拦截器
         * 对应
         *  <plugins>
         *         <plugin interceptor="zy.blue7.mybatis.test.xml.plugins.MYInsertPlugin">
         *             <property name="gupao" value="betterme"/>
         *         </plugin>
         *     </plugins>
         */
        configuration.addInterceptor(new MYInsertPlugin());



        /**
         * 添加 mapper 等同于 mapper 标签
         *      < !-- 使用相对于类路径的资源引用 -->
         * <mappers>
         *   <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
         *   <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
         *   <mapper resource="org/mybatis/builder/PostMapper.xml"/>
         * </mappers>
         *
         * <    !-- 使用完全限定资源定位符（URL） -->
         * <mappers>
         *   <mapper url="file:///var/mappers/AuthorMapper.xml"/>
         *   <mapper url="file:///var/mappers/BlogMapper.xml"/>
         *   <mapper url="file:///var/mappers/PostMapper.xml"/>
         * </mappers>
         *
         *
         * <    !-- 使用映射器接口实现类的完全限定类名 -->
         * <mappers>
         *   <mapper class="org.mybatis.builder.AuthorMapper"/>
         *   <mapper class="org.mybatis.builder.BlogMapper"/>
         *   <mapper class="org.mybatis.builder.PostMapper"/>
         * </mappers>
         *
         * <    todo !-- 将包内的映射器接口实现全部注册为映射器 -->
         * <mappers>
         *     todo 这里是 mapper 接口的包名
         *   <package name="org.mybatis.builder"/>
         * </mappers>
         *
         *
         *
         <mappers>
         <mapper resource="zy/blue7/mybatis/test/xml/mapper/PersonDao.xml"/>
         <package name="zy.blue7.mybatis.test.xml.dao"/>
         </mappers>
         */
        //todo 这两种必须只能指定一种，要么通过 接口，要么通过包名，因为他会判断，第一次设置进去了，第二次就会抛错 {@link org.apache.ibatis.binding.MapperRegistry.hasMapper}
//        configuration.addMapper(PersonDao.class);
//        configuration.addMappers("zy.blue7.mybatis.test.xml.dao");
        /**
         * todo 这个是查询指定包下的 mapper接口， 还需要满足一个条件，即， 是 第二个参数的 子类或者实现类
         */
        configuration.addMappers("zy.blue7.mybatis.test.xml.dao", Object.class);

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        return sqlSessionFactory;
    }


}
